package cn.wokoba.service.rabate.repository;


import cn.wokoba.dao.event.EventPublisher;
import cn.wokoba.dao.mapper.DailyBehaviorRebateMapper;
import cn.wokoba.dao.mapper.TaskMapper;
import cn.wokoba.dao.mapper.UserBehaviorRebateOrderMapper;
import cn.wokoba.dao.pojo.DailyBehaviorRebate;
import cn.wokoba.dao.pojo.Task;
import cn.wokoba.dao.pojo.UserBehaviorRebateOrder;
import cn.wokoba.service.rabate.model.*;
import cn.wokoba.types.enums.ResponseCode;
import cn.wokoba.types.exception.AppException;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.List;
import java.util.stream.Collectors;

@Repository
@Slf4j
public class BehaviorRebateRepository {
    @Autowired
    TaskMapper taskMapper;
    @Autowired
    EventPublisher eventPublisher;
    @Autowired
    TransactionTemplate transactionTemplate;
    @Autowired
    UserBehaviorRebateOrderMapper userBehaviorRebateOrderMapper;
    @Autowired
    DailyBehaviorRebateMapper dailyBehaviorRebateMapper;

    public void saveUserRebateRecord(String userId, List<BehaviorRebateAggregate> behaviorRebateAggregates) {
        transactionTemplate.execute(status -> {
            try {
                for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
                    BehaviorRebateOrderEntity behaviorRebateOrderEntity = behaviorRebateAggregate.getBehaviorRebateOrderEntity();
                    // 用户行为返利订单对象
                    UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
                    userBehaviorRebateOrder.setUserId(behaviorRebateOrderEntity.getUserId());
                    userBehaviorRebateOrder.setOrderId(behaviorRebateOrderEntity.getOrderId());
                    userBehaviorRebateOrder.setBehaviorType(behaviorRebateOrderEntity.getBehaviorType());
                    userBehaviorRebateOrder.setRebateDesc(behaviorRebateOrderEntity.getRebateDesc());
                    userBehaviorRebateOrder.setRebateType(behaviorRebateOrderEntity.getRebateType());
                    userBehaviorRebateOrder.setOutBusinessNo(behaviorRebateOrderEntity.getOutBusinessNo());
                    userBehaviorRebateOrder.setRebateConfig(behaviorRebateOrderEntity.getRebateConfig());
                    userBehaviorRebateOrder.setBizId(behaviorRebateOrderEntity.getBizId());
                    userBehaviorRebateOrderMapper.insert(userBehaviorRebateOrder);
                    // 任务对象
                    TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
                    Task task = new Task();
                    task.setUserId(taskEntity.getUserId());
                    task.setTopic(taskEntity.getTopic());
                    task.setMessageId(taskEntity.getMessageId());
                    task.setMessage(JSON.toJSONString(taskEntity.getMessage()));
                    task.setState(taskEntity.getState().getCode());
                    taskMapper.insert(task);
                }
                return 1;
            } catch (DuplicateKeyException e) {
                status.setRollbackOnly();
                log.error("写入返利记录，唯一索引冲突 userId: {}", userId, e);
                throw new AppException(ResponseCode.INDEX_DUP.getCode(), e);
            }
        });

        // 同步发送MQ消息
        for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
            TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
            Task task = new Task();
            task.setUserId(taskEntity.getUserId());
            task.setMessageId(taskEntity.getMessageId());
            try {
                // 发送消息【在事务外执行，如果失败还有任务补偿】
                eventPublisher.publish(taskEntity.getTopic(), taskEntity.getMessage());
                // 更新数据库记录，task 任务表
                taskMapper.updateTaskSendMessageCompleted(task);
            } catch (Exception e) {
                log.error("写入返利记录，发送MQ消息失败 userId: {} topic: {}", userId, task.getTopic());
                taskMapper.updateTaskSendMessageFail(task);
            }
        }
    }

    public List<DailyBehaviorRebateVO> queryDailyBehaviorRebateConfig(BehaviorTypeVO behaviorTypeVO) {
        List<DailyBehaviorRebate> dailyBehaviorRebates = dailyBehaviorRebateMapper.selectList(Wrappers.<DailyBehaviorRebate>lambdaQuery()
                .eq(DailyBehaviorRebate::getState, "open"));
        return dailyBehaviorRebates.stream().map(
                dailyBehaviorRebate -> DailyBehaviorRebateVO.builder()
                        .behaviorType(dailyBehaviorRebate.getBehaviorType())
                        .rebateDesc(dailyBehaviorRebate.getRebateDesc())
                        .rebateType(dailyBehaviorRebate.getRebateType())
                        .rebateConfig(dailyBehaviorRebate.getRebateConfig())
                        .build()).collect(Collectors.toList());
    }

    public List<BehaviorRebateOrderEntity> queryOrderByOutBusinessNo(String userId, String outBusinessNo) {
        List<UserBehaviorRebateOrder> userBehaviorRebateOrderResList = userBehaviorRebateOrderMapper.selectList(Wrappers.<UserBehaviorRebateOrder>lambdaQuery()
                .eq(UserBehaviorRebateOrder::getUserId, userId)
                .eq(UserBehaviorRebateOrder::getOutBusinessNo, outBusinessNo));

        return userBehaviorRebateOrderResList.stream()
                .map(userBehaviorRebateOrder -> BehaviorRebateOrderEntity.builder()
                        .userId(userBehaviorRebateOrder.getUserId())
                        .orderId(userBehaviorRebateOrder.getOrderId())
                        .behaviorType(userBehaviorRebateOrder.getBehaviorType())
                        .rebateDesc(userBehaviorRebateOrder.getRebateDesc())
                        .rebateType(userBehaviorRebateOrder.getRebateType())
                        .rebateConfig(userBehaviorRebateOrder.getRebateConfig())
                        .outBusinessNo(userBehaviorRebateOrder.getOutBusinessNo())
                        .bizId(userBehaviorRebateOrder.getBizId())
                        .build()).toList();
    }
}
